//
//  IDONumberJumpUitls.m
//  IDODashboardView
//
//  Created by 卓勇 on 2017/3/11.
//  Copyright © 2017年 idozhuoyong. All rights reserved.
//

#import "IDONumberJumpUitls.h"

typedef struct
{
    float x;
    float y;
}Point2D;


/**
 参考：http://code4app.com/ios/NJDNumberJump/53b500c3933bf0b2118b51ad
 */
@interface IDONumberJumpUitls ()

@property (nonatomic, assign) int jumpNumber; // 跳动次数
@property (nonatomic, assign) int currentJumpNumber; // 当前跳动次数
@property (nonatomic, assign) double duration; // 跳动时间
@property (nonatomic, assign) double lastTime; // 最近一次跳动时间
@property (nonatomic, assign) double startNumber; // 开始跳动数字
@property (nonatomic, assign) double endNumber; // 结束跳动数字

@property (nonatomic, strong) NSMutableArray *numberPointDatas;

@property (nonatomic, copy) NumberJumpBlock numberJumpBlock;

@end


@implementation IDONumberJumpUitls

- (void)jumpNumberWithDuration:(double)duration fromNumber:(double)startNumber toNumber:(double)endNumber numberJumpBlock:(NumberJumpBlock)numberJumpBlock {
    self.duration = duration; // 跳动时间
    self.startNumber = startNumber; // 开始跳动数字
    self.endNumber = endNumber; // 结束跳动数字
    self.numberJumpBlock = numberJumpBlock;
    
    [self initParameters];
    
    [self changeNumber];
}

- (void)initParameters {
    self.jumpNumber = 100; // 跳动次数
    self.currentJumpNumber = 0; // 当前跳动次数
    self.lastTime = 0; // 最近一次跳动时间
    
    // 可到http://cubic-bezier.com自定义贝塞尔曲线
    Point2D startPoint;
    startPoint.x = 0;
    startPoint.y = 0;
    
    Point2D controllerPoint1;
    controllerPoint1.x = 0.25;
    controllerPoint1.y = 0.1;
    
    Point2D controllerPoint2;
    controllerPoint2.x = 0.25;
    controllerPoint2.y = 0.1;
    
    Point2D endPoint;
    endPoint.x = 1;
    endPoint.y = 1;
    
    Point2D point2Ds[4] = {startPoint, controllerPoint1, controllerPoint2, endPoint};
    
    self.numberPointDatas = [NSMutableArray array];
    for (int i = 0; i < self.jumpNumber; i++) {
        Point2D point = PointOnCubicBezier(point2Ds, i * (1.0 / (self.jumpNumber - 1)));
        float durationTime = point.x * self.duration; // 时间
        float value = point.y * (_endNumber - _startNumber) + _startNumber; // 数字
        [self.numberPointDatas addObject:[NSArray arrayWithObjects:[NSNumber numberWithFloat:durationTime], [NSNumber numberWithFloat:value], nil]];
    }
}

- (void)changeNumber {
    if (self.currentJumpNumber >= self.jumpNumber) {
        // 赋值
        //NSLog(@"%f", self.endNumber);
        if (self.numberJumpBlock) {
            self.numberJumpBlock(self.endNumber);
        }
    } else {
        NSArray *values = [self.numberPointDatas objectAtIndex:self.currentJumpNumber];
        double currentTime = [[values objectAtIndex:0] doubleValue];
        double value = [[values objectAtIndex:1] doubleValue];
        double timeDuration = currentTime - self.lastTime;
        // NSLog(@"%f --- %f --- %f", currentTime, self.lastTime, timeDuration);
        
        // 赋值
        //NSLog(@"%f", value);
        if (self.numberJumpBlock) {
            self.numberJumpBlock(value);
        }
        
        self.lastTime = currentTime;
        self.currentJumpNumber++;
        [self performSelector:@selector(changeNumber) withObject:nil afterDelay:timeDuration];
    }
}

/* cp 在此是四个元素的数组:
 cp[0] 为起点，或上图中的 P0
 cp[1] 为第一控制点，或上图中的 P1
 cp[2] 为第二控制点，或上图中的 P2
 cp[3] 为结束点，或上图中的 P3
 t 为参数值，0 <= t <= 1 */
Point2D PointOnCubicBezier( Point2D* cp, float t )
{
    // x = (1-t)^3 *x0 + 3*t*(1-t)^2 *x1 + 3*t^2*(1-t) *x2 + t^3 *x3
    // y = (1-t)^3 *y0 + 3*t*(1-t)^2 *y1 + 3*t^2*(1-t) *y2 + t^3 *y3
    float   ax, bx, cx;
    float   ay, by, cy;
    float   tSquared, tCubed;
    Point2D result;
    
    /*計算多項式係數*/
    cx = 3.0 * (cp[1].x - cp[0].x);
    bx = 3.0 * (cp[2].x - cp[1].x) - cx;
    ax = cp[3].x - cp[0].x - cx - bx;
    
    cy = 3.0 * (cp[1].y - cp[0].y);
    by = 3.0 * (cp[2].y - cp[1].y) - cy;
    ay = cp[3].y - cp[0].y - cy - by;
    
    /*計算位於參數值t的曲線點*/
    tSquared = t * t;
    tCubed = tSquared * t;
    
    result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
    result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
    
    return result;
}

@end
